package com.hyc.www.service.impl;

import com.hyc.www.dao.OrderDao;
import com.hyc.www.dao.TicketDao;
import com.hyc.www.factory.DaoProxyFactory;
import com.hyc.www.model.po.Order;
import com.hyc.www.model.po.Ticket;
import com.hyc.www.service.TicketDistributor;
import com.hyc.www.util.JdbcUtils;

import java.math.BigInteger;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.*;

import static com.hyc.www.util.UUIDUtils.getUUID;

/**
 * @author <a href="mailto:kobe524348@gmail.com">黄钰朝</a>
 * @description 负责车票分发
 * @date 2019-07-18 19:43
 */
public class TicketDistributorImpl implements TicketDistributor {

    private final TicketDao ticketDao = (TicketDao) DaoProxyFactory.getInstance().getProxyInstance(TicketDao.class);
    private final OrderDao orderDao = (OrderDao) DaoProxyFactory.getInstance().getProxyInstance(OrderDao.class);
    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(30, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory());

    private static TicketDistributorImpl instance = new TicketDistributorImpl();

    private TicketDistributorImpl() {
    }

    public static TicketDistributorImpl getInstance() {
        return instance;
    }

    private static final Map<BigInteger, InventoryCache> cacheMap = new ConcurrentHashMap();


    /**
     * 用于返回系统中该id对应的空闲车票
     *
     * @param id     车票id
     * @param number 车票数量
     * @return 返回一个车票订单集合，用户线程获取一张车票后填入个人id即抢票成功
     * @name getTicketList
     * @notice none
     * @author <a href="mailto:kobe524348@gmail.com">黄钰朝</a>
     * @date 2019-07-18
     */
    @Override
    public synchronized Queue<Order> getAvailableTickets(BigInteger id, int number) {

        int ticketNum = 0;
        Queue<Order> orderList = new ConcurrentLinkedQueue<>();
        //使用事务
        Connection connection = JdbcUtils.getConnection();
        try {
            connection.setAutoCommit(false);
            Ticket ticket = TicketDao.getTicketById(connection, id);
            //无票直接返回
            if (ticket == null || ticket.getInventory() == 0) {
                return null;
            } else if (ticket.getInventory() > number) {
                ticketNum = number;
                //取出number张票
                ticket.setInventory(ticket.getInventory() - number);
            } else {
                //取出所有余票
                ticketNum = ticket.getInventory();
                ticket.setInventory(0);
            }
            //更新到数据库
            TicketDao.update(connection, ticket);
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            try {
                connection.commit();
                connection.setAutoCommit(true);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            JdbcUtils.close(connection);
        }

        //创建list
        for (int i = 0; i < ticketNum; i++) {
            Order order = new Order();
            order.setTicketId(id);
            order.setNumber(getUUID());
            orderList.add(order);
        }
        return orderList;
    }


    public InventoryCache getInventoryCache(BigInteger ticketId) {
        //获取库存，如果没有则新建
        synchronized (cacheMap) {
            if (cacheMap.get(ticketId) == null) {
                Ticket ticket = ticketDao.getTicketById(ticketId);
                InventoryCache cache = new InventoryCache(ticketId);
                if (ticket == null) {
                    return null;
                } else {
                    //新建时更新库存
                    cache.setInventory(ticket.getInventory());
                    EXECUTOR.execute(cache);
                }
                cacheMap.put(ticketId, cache);
                return cache;
            } else {
                return cacheMap.get(ticketId);
            }
        }
    }


    class InventoryCache implements Runnable {
        private int inventory = 0;
        private final BigInteger ticketId;
        private final LinkedBlockingDeque<Order> REQ_QUEUE = new LinkedBlockingDeque();


        InventoryCache(BigInteger ticketId) {
            this.ticketId = ticketId;
        }

        public int getInventory() {
            return inventory;
        }

        public void setInventory(int inventory) {
            this.inventory = inventory;
        }

        public LinkedBlockingDeque getREQ_QUEUE() {
            return REQ_QUEUE;
        }

        void updateInventory() {
            Ticket ticket = ticketDao.getTicketById(ticketId);
            inventory = ticket.getInventory();
        }

        void decreInventory() {
            inventory = inventory - 1;
        }


        @Override
        public void run() {
            while (true) {
                if (REQ_QUEUE.size() == 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    Order order = REQ_QUEUE.removeLast();
                    order.setNumber(getUUID());
                    orderDao.insert(order);
                    System.out.println("打印订单信息：ticketId= " + order.getTicketId() + "  userId = " + order.getUserId() + " number = " + order.getNumber());

                }
            }
        }
    }


}
